package auctionhausen

import static org.junit.Assert.*

import org.junit.*

class BidIntegrationTests {

	@Before
	void setUp() {
		// Setup logic here
	}

	@After
	void tearDown() {
	}

	// B-5: The Bid amount must be at least .50 higher than the previous Bid 
	//		for the same listing
	// Note: We are using the failOnError argument when saving a Listing with
	//		 an invalid bid increment. This will cause a ValidationException to
	//		 be thrown.
	@Test(expected = grails.validation.ValidationException)
	void testBidAmountGreaterThanThreshold() {
		//create and save customers
		def steve = new Customer(email: 'steve@bland.com', password: 'pa55word')
		steve.save(flush : true)
		assertFalse steve.hasErrors()

		def roger = new Customer(email: 'roger@rabbit.com', password: 'jeopardy')
		roger.save(flush : true)
		assertFalse roger.hasErrors()

		//create listing
		def listing = new Listing(
				seller: steve,
				name: 'Used Tricycle',
				endDate: new Date()+3,
				startingPrice: 5.00,
				description: 'Like new!')

		//save the listing and verify that no errors occured
		listing.save(flush:true)
		
		//add a bid for each user
		listing.addToBids(new Bid(amount: 5.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		
		//note increment == to $.50 minimum bid increment value 
		listing.addToBids(new Bid(amount: 5.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		//note increment >  $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 6.25, bidder: roger))
		listing.save(flush:true, failOnError:true)
		
		//attempt to add a new bid that is < the $.50 minimum increment
		listing.addToBids(new Bid(amount: 5.60, bidder: steve))
		
		//use the failOnError argument to for an exception when validation fails
		listing.save(flush:true, failOnError:true)
	}

	// B-6: When a Listing is saved, any new Bids added for the listing must be saved
	@Test
	void testBidsAreSaveWhenTheirOwningListingIsSaved() {
		//create and save customers
		def steve = new Customer(email: 'steve@bland.com', password: 'pa55word')
		steve.save(flush : true)
		assertFalse steve.hasErrors()

		def roger = new Customer(email: 'roger@rabbit.com', password: 'jeopardy')
		roger.save(flush : true)
		assertFalse roger.hasErrors()

		//create listing
		def listing = new Listing(
				seller: steve,
				name: 'Used Tricycle',
				endDate: new Date()+3,
				startingPrice: 5.00,
				description: 'Like new!')

		//save the listing and verify that no errors occured
		listing.save(flush:true)
		
		//verify validations and saves for each bid succeeded
		assertFalse listing.hasErrors()
		
		//add a bid for each user
		listing.addToBids(new Bid(amount: 5.00, bidder: roger))
		listing.addToBids(new Bid(amount: 5.50, bidder: steve))

		//save the listing and verify that no errors occured
		listing.save(flush:true)
		assertFalse listing.hasErrors()

		//retrieve all available bids
		def bids = Bid.getAll();
		
		//verify that the 2 bids where saved when their owning Listing was saved
		assertTrue 2 <= bids.size()
	}
	
	// UI-1: The listing detail page will asynchronously load and display a
	// list of the last 10 bids placed on the item showing the user, date/time,
	// and amount. The implementation of the lookup of these results must be
	// done with a Named Query.
	@Test
	void testGetMostRecentBidsForListing() {
		//create and save customers
		def steve = new Customer(email: 'steve@bland.com', password: 'pa55word')
		steve.save(flush : true)
		assertFalse steve.hasErrors()

		def roger = new Customer(email: 'roger@rabbit.com', password: 'jeopardy')
		roger.save(flush : true)
		assertFalse roger.hasErrors()

		//create listing
		def listing = new Listing(
				seller: steve,
				name: 'Used Tricycle',
				endDate: new Date()+3,
				startingPrice: 5.00,
				description: 'Like new!')
		
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 6.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 6.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 7.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 7.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 8.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 8.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 9.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 9.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 10.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		//note increment >= $.50 minimum bid increment value
		listing.addToBids(new Bid(amount: 10.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		// Add 11th and 10th bids, that won't be displayed.
		listing.addToBids(new Bid(amount: 11.00, bidder: roger))
		listing.save(flush:true, failOnError:true)
		listing.addToBids(new Bid(amount: 11.50, bidder: steve))
		listing.save(flush:true, failOnError:true)
		
		def tenMostRecentBids = Bid.recentBidsOnListing(listing).list()
		
		assertTrue tenMostRecentBids.size() == 1
	}
}
